#include "my_ipc.h"
// 创建共享内存区
int create_shm(int mykey, int size) {
    int shmid = shmget(mykey, size, IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget error");
        #ifdef DEBUG
        fprintf(stderr, "Error details: key=%d, size=%d, errno=%d (%s)\n",
               mykey, size, errno, strerror(errno));
        verify_key(mykey);
        #endif
        exit(1);
    }
    return shmid;
}

// 返回指定的共享内存区
void* get_shm(int shmid) {
    void* retshm = shmat(shmid, (void*)0, 0);
    if (retshm == (void*)-1) {
        perror("shmat error");
        exit(1);
    }
    return retshm;
}

// 断开共享内存区
void disconnect_shm(void *shmaddr) {
    if (shmdt(shmaddr) == -1) {
        perror("shmdt error");
        exit(1);
    }
}

// 删除共享内存区
void delete_shm(int shmid) {
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        if(is_shmid_valid(shmid)){
            fprintf(stderr, "Error: shmid %d is still valid.\n", shmid); 
        }
        else{
            //fprintf(stderr, "Error: shmid %d is not valid.\n", shmid);
            return; 
        }
        #ifdef DEBUG
        fprintf(stderr, "Error details: shmid=%d, errno=%d (%s)\n",
               shmid, errno, strerror(errno));
        #endif
        perror("shmctl error");
        exit(1);
    }
}

// 建立信号量
int creat_sem(int mykey, int semval, int semnum) {
    if (semval < 0) {
        fprintf(stderr, "Error: Semaphore value cannot be negative (val=%d)\n", semval);
        exit(EXIT_FAILURE);
    }
    
    if (semnum <= 0 || semnum > 250) {  // 假设系统限制为250
        fprintf(stderr, "Error: Invalid semaphore count (count=%d)\n", semnum);
        exit(EXIT_FAILURE);
    }
    fprintf(stderr, "Creating semaphore with key=%d, value=%d, count=%d\n", mykey, semval, semnum);
    int semid = semget(mykey, semnum, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("semget error");
        exit(1);
    }
    union semun sem_union;
    sem_union.val = semval;
    int i;
    for (i = 0; i < semnum; i++) {
        if (semctl(semid, i, SETVAL, sem_union) == -1) {
            perror("semctl(SETVAL) error");
            exit(1);
        }
    }
    return semid;
}

// 等待信号量
void Wait(int sid, int sem_num) {
    struct sembuf op;
    op.sem_num = sem_num;
    op.sem_op = -1;
    op.sem_flg = 0;
    if (semop(sid, &op, 1) == -1) {
        perror("semop error");
        exit(1);
    }
}

// 通过信号量
void Signal(int sid, int sem_num) {
    struct sembuf op;
    op.sem_num = sem_num;
    op.sem_op = 1;
    op.sem_flg = 0;
    if (semop(sid, &op, 1) == -1) {
        perror("semop error");
        exit(1);
    }
}

// 删除信号量
void delete_sem(int semid) {
    if (semctl(semid, 0, IPC_RMID) == -1) {
        if(is_semid_valid(semid)){
            fprintf(stderr, "Error: semid %d is still valid.\n", semid);
        }else{
            //fprintf(stderr, "Error: semid %d is not valid.\n", semid);
            return;
        }
        #ifdef DEBUG
        fprintf(stderr, "Error details: semid=%d, errno=%d (%s)\n",
               semid, errno, strerror(errno));
        #endif
        perror("semctl error");
        exit(1);
    }
}

int is_semid_valid(int semid) {
    if (semid < 0) {
        return 0; // 无效ID（负数）
    }

    struct semid_ds buf;
    // 使用 IPC_STAT 获取信号量状态
    if (semctl(semid, 0, IPC_STAT, &buf) == -1) {
        perror("semctl(IPC_STAT) failed");
        return 0; // 无效
    }
    return 1; // 有效
}
int is_shmid_valid(int shmid) {
    if (shmid < 0) {
        return 0; // 无效ID（负数）
    }

    struct shmid_ds buf;
    // 使用 IPC_STAT 获取共享内存状态
    if (shmctl(shmid, IPC_STAT, &buf) == -1) {
        perror("shmctl(IPC_STAT) failed");
        return 0; // 无效
    }
    return 1; // 有效 
}
void verify_key(int key) {
    // 检查键值范围
    if (key <= 0 || key >= 0xfffffff0) {
        fprintf(stderr, "Invalid key value: %d\n", key);
        exit(1);
    }

    // 检查是否已被占用
    int shmid = shmget(key, 0, 0666);
    if (shmid != -1) {
        struct shmid_ds buf;
        shmctl(shmid, IPC_STAT, &buf);
        fprintf(stderr, "Key conflict: key=%d, shmid=%d, creator_pid=%d\n",
               key, shmid, buf.shm_cpid);
        exit(1);
    }

    printf("Key %d is available\n", key);
}

